fix(core-net): cast uint32_t grace_us for %u format specifier#3618
Open
vikramdattu wants to merge 45 commits into
Open
fix(core-net): cast uint32_t grace_us for %u format specifier#3618vikramdattu wants to merge 45 commits into
vikramdattu wants to merge 45 commits into
Conversation
The mbedTLS 4 migration handled the generic (non-FreeRTOS) include branch but missed the FreeRTOS paths, so an ESP-IDF v6 / mbedTLS 4 build hits removed-header errors: - private-lib-tls.h includes <mbedtls/aes.h> and <mbedtls/gcm.h> unconditionally in the FreeRTOS branch; both were removed in mbedTLS 4. Gate behind !LWS_HAVE_MBEDTLS_V4, mirroring the generic branch. - freertos-sockets.c includes the legacy <mbedtls/net.h> (removed in mbedTLS 4) when LWS_HAVE_MBEDTLS_NET_SOCKETS is unset, which it always is on FreeRTOS since the probe doesn't run there. Include <mbedtls/net_sockets.h> on mbedTLS 4: it still carries mbedtls_net_context and the MBEDTLS_ERR_NET_* codes used by the BIO callbacks even when MBEDTLS_NET_C is off. Verified on a real IDF v6 / mbedTLS 4 build.
The m==16 (IPv6) numeric-literal path used ai/sa46 without deriving them from the cache entry c, unlike the m==4 (IPv4) path just above. When the cache entry already existed (the allocation block was not entered), ai/sa46 were uninitialised, which GCC flags as -Werror=maybe-uninitialized with IPv6 enabled. Mirror the IPv4 path.
Subject: [PATCH] freertos: don't leave SPAWN (and its siginfo_t dep) enabled LWS_WITH_STUB defaults ON and implies LWS_WITH_SPAWN in CMakeLists-implied-options.txt before the LWS_PLAT_FREERTOS block disables STUB, so SPAWN stays on for FreeRTOS. There is no spawn support on FreeRTOS, and the spawn API's siginfo_t typedef fails to build with newer newlib (ESP-IDF v6). Force SPAWN off in the FreeRTOS block.
The OpenSSL-compat wrapper selects net_sockets.h over the v4-removed net.h, and the MBEDTLS_SSL_NEW_SESSION_TICKET enum, via the LWS_HAVE_MBEDTLS_NET_SOCKETS / LWS_HAVE_MBEDTLS_SSL_NEW_SESSION_TICKET probes. Those don't run on FreeRTOS, so on an mbedTLS 4 build there the v3 branch is compiled and breaks. Also accept LWS_HAVE_MBEDTLS_V4 so the v4 path is taken wherever that's set.
IDF v6 switched to picolibc, whose errno is thread-local. lws forces
LWIP_PROVIDE_ERRNO and declares its own `extern int errno`, both
non-TLS, so objects fail to link against picolibc's TLS errno
("TLS definition ... mismatches non-TLS reference"). On mbedTLS 4
(a proxy for IDF v6) skip LWIP_PROVIDE_ERRNO and include <errno.h>
instead. Older IDF (newlib) is unchanged.
If lws_client_connect_via_info() never fully completes (e.g., DNS not resolvable, but glibc is waiting?), the ah allocated during the h1 connect sequence is still attached to the wsi, even though it is "pre-natal". While we're in this state, before the connection failure is handled, if the user ends up calling lws_context_destroy() e.g., in a libuv foreign loop, the ah pool is freed first. However, the wsi still has a dangling pointer to the ah. Then in a later part of the context destroy sequence, lws_pt_destroy() loops through the pre-natal wsis, and eventually accesses and dereferences the dangling wsi->http.ah pointer. In _lws_destroy_ah(), detach the wsi->http.ah pointer when we free it. This seems safest, since _lws_destroy_ah() is called in a handful of contexts.
…u list is empty lws_cache_item_evict_lru() silently does nothing when the lru list is empty, but the eviction loop in lws_cache_heap_write() only checks the footprint / item count limits. If the limits still appear exceeded after the cache has been fully emptied (eg, a single item larger than max_footprint, or a stale current_footprint inherited from the pre-existing accounting bug), the loop condition never changes and the service thread spins forever inside the write, never returning to the event loop. Signed-off-by: minicx <minicx@disroot.org>
lws frees wsi->stash early in lws_http_client_connect_via_info2() when LWS_WITH_SOCKS5 is enabled (even without an actual SOCKS5 proxy). lws_cookie_write_nsc() handles this with a fallback to lws_hdr_simple_ptr(), but lws_cookie_attach_cookies() did not, returning -1 immediately when stash was NULL. This caused cookie jar lookups to silently fail on builds with LWS_WITH_SOCKS5 enabled (e.g. txiki.js on Linux), while working on those without it (e.g. Android builds). Add the same header-based fallback to lws_cookie_attach_cookies(), matching the existing pattern in lws_cookie_write_nsc().
Signed-off-by: stropee <simon@sirocha.fr>
Signed-off-by: stropee <simon@sirocha.fr>
… in iface field on FreeRTOS/LwIP Signed-off-by: stropee <simon@sirocha.fr>
Signed-off-by: stropee <simon@sirocha.fr>
On Windows, send() expects int for the third argument (len), but socks5-client.c was casting the ssize_t value to (size_t). MSVC at /W3 warns C4267 about the implicit narrowing from size_t (64-bit) to int (32-bit), and with /WX the warning becomes a fatal error (C2220). Fix the two send() sites by adding an explicit (int) cast guarded with #if defined(WIN32), matching the existing pattern used in output.c. AG: use helper and fixup similar cases Ref: txiki.js CI build (error C2220 at socks5-client.c:239,64)
We leave lws_buflist as it is since it is a public api. We introduce an alternative solution lws_buflist2. It offers a similar api to lws_buflist, but it is based on lws_dll2_owner. - its footprint in the using struct is an lws_buflist2_owner. - allocations are tracked using lws_dll2... that solves problems that lws_buflist has having to iterate to find the tail, or total size, it already always tracks the tail and allocated size. - You can set the sanity limit size per-owner (lws_buflist is fixed)
Integrate OpenHiTLS as a new TLS backend option for libwebsockets, providing an alternative to OpenSSL, mbedTLS, and other TLS libraries. Core changes: - CMake detection and build configuration for OpenHiTLS - Complete TLS client and server implementation - X.509 certificate operations (parse, verify, load) - Crypto primitives: AES, RSA, EC, Hash operations - TLS 1.2 and TLS 1.3 support with session management - SNI, ALPN, and keylog callback support - BSL_UIO wrapper layer for OpenHiTLS I/O abstraction Technical details: - New cmake/FindOpenHITLS.cmake for library detection - Backend-specific code in lib/tls/openhitls/ - Integration with lws TLS abstraction layer - Support for both memory and file-based certificates - Error mapping between OpenHiTLS and lws error codes
rops_perform_user_POLLOUT_h2() ends by calling lws_wsi_mux_action_pending_writeable_reqs(), which decides POLLOUT purely from child streams' requested_POLLOUT and clears POLLOUT when no child wants it. It ignores the network connection's own queued protocol sends (wsi->h2.h2n->pps), e.g. a connection- or stream-level WINDOW_UPDATE that grants the peer receive-window credit. When such a pps is queued but no child stream currently wants POLLOUT, POLLOUT is cleared and the pps is never flushed, so the peer never gets the credit and the transfer stalls. This is easy to hit on the client with a bodyless request (e.g. a plain GET): the request stream goes HALF_CLOSED_LOCAL as soon as the headers are sent with END_STREAM, so no child wants POLLOUT, while the netconn still needs to emit the WINDOW_UPDATE that opens the receive window. The response headers arrive but the body stalls at the flow-control window (the stream window, or 65535 at the connection level) until the peer resets the stream. Fix: keep POLLOUT asserted while the netconn still has pps pending, before falling through to the child-only reconciler. Observed only with the mbedtls TLS backend; the byte-identical code under GnuTLS/OpenSSL happens to flush via different read/POLLOUT interleaving, which is likely why this has gone unnoticed.
lws_h2_bind_for_post_before_action() delivers any request-body bytes that were stashed on the stream buflist while the stream was in LRS_DEFERRING_ACTION, decrementing rx_content_length as it goes. But the inline DATA path in lws_read_h1() and the HTTP_BODY_COMPLETION decision both track rx_content_remain (initialized to the full content-length), not rx_content_length. When a request body is split across the DEFERRING_ACTION boundary -- part stashed and dumped here, the rest arriving later on the inline path -- rx_content_remain is never reduced for the stashed part, so it can never reach 0. HTTP_BODY_COMPLETION therefore never fires and the request hangs until it times out. Bodies small enough to be fully stashed complete via the explicit callback at the end of this function, which is why only larger/split POST bodies were affected. Keep rx_content_remain in step with rx_content_length as the stashed body is delivered.
The lws_hdr_custom_*() accessors read unknown headers out of the ah's UHO linked list, but that list was only ever populated by the h1 text header parser; for h2 the accessors early-returned on mux_substream and custom headers were invisible (commit da8995b disabled the speculative h1 path for substreams). The h1 path can't be reused as-is for h2: the header name arrives through hpack one character at a time (fed to lws_parse purely for known-header recognition) and the value never passes through the h1 unknown-value collector at all, so neither the name nor the value were being stored. Build the UHO entry directly in the hpack decoder instead, where both the name and value bytes are available: - reserve the UHO entry header before the name (speculatively, per the h1 approach), - collect the name as it decodes, finalizing it (with the trailing ':' the accessors expect) and linking it into unk_ll when lws does not recognize the header, or dropping it if it does, - collect the value bytes that the IGNORE-entry path otherwise discards, - record the value length when the value completes. To keep a single writer of ah->pos during substream name parsing, the h1 text parser no longer also lays the name bytes down for mux substreams. Relax the mux_substream guard on the three lws_hdr_custom_*() accessors so the now-populated list is readable for h2.
…ADERS A client sends "no request body" over HTTP/2 by setting END_STREAM on the HEADERS frame and omitting Content-Length (e.g. an empty POST). lws_http_action() re-derives the body expectation from the Content-Length header and the method: for a body-bearing method with no Content-Length it defaults rx_content_length to 100MB and waits for DATA frames that, after END_STREAM, will never arrive -- so the request stalls until it times out. (An explicit "Content-Length: 0" works, because that takes the explicit-zero path.) For a mux (h2) substream whose END_STREAM already arrived with the HEADERS and that carried no Content-Length, treat the body as an explicit zero-length body, exactly as "Content-Length: 0" would. h3 already does the equivalent in ops-h3.c. Fixes empty-body POST/PUT/PATCH over h2 hanging server-side (reproduces with `curl --http2 -X POST` against any lws h2 server).
The mbedtls server and client bio setup assigned lws_sockfd_type directly to mbedtls_net_context.fd, which is an int. On Win64 lws_sockfd_type is SOCKET (a 64-bit UINT_PTR), so MSVC warns C4244 "possible loss of data", which fails the build under /WX. Add an explicit (int) cast, matching the gnutls and openhitls backends which already cast the same sockfd the same way.
DISABLE_WERROR only gated the GCC/Clang -Werror flag; the MSVC branch added /WX unconditionally, so setting DISABLE_WERROR=ON had no effect when building with MSVC. Gate /WX on DISABLE_WERROR the same way the GCC/Clang path does, leaving /W3 (the warning level) always enabled.
connect3.c logs grace_us (uint32_t) with %u. On toolchains where uint32_t is 'long unsigned int' (e.g. xtensa-esp-elf for ESP-IDF v5.3/v5.4) this trips -Werror=format and fails the build. Cast to unsigned int to match the specifier; the value (grace timer in us) always fits.
|
4e74eb8 to
0013069
Compare
vikramdattu
added a commit
to vikramdattu/esp-protocols
that referenced
this pull request
Jun 20, 2026
warmcat/libwebsockets#3618 (cast uint32_t grace_us for the %u format specifier in connect3.c) is now on main, so move the pin forward from the temporary parent-commit pin to current main (00130694a). Verified: examples/client builds clean on ESP-IDF v6.0 (esp32).
6eecf5a to
b4b5aed
Compare
cc71944 to
ff5a3aa
Compare
348d445 to
ef50ad9
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.



Problem
lib/core-net/client/connect3.clogsgrace_us(auint32_t) with a%uspecifier:On toolchains where
uint32_tis typedef'd aslong unsigned int(e.g.xtensa-esp-elffor ESP-IDF v5.3 / v5.4),%u(which expectsunsigned int) mismatches the argument type and trips-Werror=format, failing the build:(Found while building libwebsockets as a component on ESP-IDF. Toolchains where
uint32_tisunsigned intdon't warn, so it only shows on some targets.)Fix
Cast to
unsigned intto match the%uspecifier — matching the existing logging idiom in core-net (rather than pulling inPRIu32). The value is a grace timer in microseconds and always fits.